package parser;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

public class JavaNet
{
    // the static variables to denote the form for output data
    public static int      XML        = 1;
    public static int      TEXT       = 2;

    // the parse form for the file
    public static int      FILE       = 3;
    public static int      DIRECTORY  = 4;

    // basic variable stores the path information
    private String         input      = "";
    private String         output     = "./result.txt";

    // the basic form the parse process and the output text
    private int            outputForm = JavaNet.TEXT;
    private int            parseForm  = JavaNet.FILE;

    // io data for the parser
    private BufferedWriter textWriter;
    private BufferedWriter xmlWriter;

    // log file
    private String         log        = "log.txt";
    private BufferedWriter logWriter;

    /*
     * constructor
     */
    public JavaNet()
    {
    }

    // /////////////////////////////////////
    public void setInputPath(String input)
    {
        this.input = input;
    }

    // ////////////////////////////////////////
    public void setOutputPath(String output)
    {
        this.output = output;
    }

    // //////////////////////////////////////
    public void setOutputForm(int form)
    {
        this.outputForm = form;
    }

    // //////////////////////////////////////
    public void setParseForm(int form)
    {
        this.parseForm = form;
    }

    // //////////////////////////////////////
    public void parse()
    {
        try
        {
            this.logWriter = new BufferedWriter(new OutputStreamWriter(
                    new FileOutputStream(this.log)));
        } catch (Exception e)
        {
            e.printStackTrace();
            return;
        }
        // output form is text file, then create the corresponding
        // output buffered stream object
        if (this.outputForm == JavaNet.TEXT)
        {
            try
            {
                this.textWriter = new BufferedWriter(new OutputStreamWriter(
                        new FileOutputStream(this.output)));

                if (this.parseForm == JavaNet.FILE)
                {
                    parseFile(this.input);
                } else
                {
                    parsePath(this.input);
                }

                Tool.genTextFile(this.textWriter);
                this.textWriter.flush();
                this.textWriter.close();
            } catch (Exception e)
            {
                e.printStackTrace();
                return;
            }
        }
        // the output form is xml file
        else
        {
            try
            {
                this.xmlWriter = new BufferedWriter(new OutputStreamWriter(
                        new FileOutputStream(this.output)));
                if (this.parseForm == JavaNet.FILE)
                {
                    parseFile(this.input);
                } else
                {
                    parsePath(this.input);
                }

                Tool.genXmlFile(this.xmlWriter);
                this.xmlWriter.flush();
                this.xmlWriter.close();
            } catch (Exception e)
            {
                e.printStackTrace();
                return;
            }
        }

        try
        {
            this.logWriter.flush();
            this.logWriter.close();
        } catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    // ////////////////////////////////////////////////
    private void parseFile(String path)
    {
        // System.out.println("path: " + path);
        try
        {
            InputStreamReader reader = new InputStreamReader(
                    new FileInputStream(new File(path)));
            JavaNetParser parser = new JavaNetParser(reader);
            parser.CompilationUnit();

            // output the file
            // if(outputForm == JavaNet.TEXT) Tool.genTextFile(textWriter,
            // parser);
            Tool.collectData(parser);
        } catch (Exception e)
        {
            try
            {
                this.logWriter.write("Ignore file : " + path + ". \n");
                if (TokenMgrError._error == TokenMgrError._LEXICAL_ERROR)
                {
                    this.logWriter.write("Lexical error at line "
                            + TokenMgrError._errorLine
                            + ", column "
                            + TokenMgrError._errorColumn
                            + ".  Encountered: "
                            + (TokenMgrError._EOFSeen ? "<EOF> " : "\""
                                    + TokenMgrError.addEscapes(String
                                            .valueOf(TokenMgrError._curChar))
                                    + "\"" + " ("
                                    + (int) TokenMgrError._curChar + "), ")
                            + "after : \""
                            + TokenMgrError
                                    .addEscapes(TokenMgrError._errorAfter)
                            + "\"\n\n");
                    TokenMgrError._error = TokenMgrError._NO_ERROR;
                } else
                    if (TokenMgrError._error == TokenMgrError._PARSER_ERROR)
                    {
                        this.logWriter.write(e.getMessage() + "\n\n");
                        TokenMgrError._error = TokenMgrError._NO_ERROR;
                    } else
                    {
                        e.printStackTrace();
                    }
            } catch (Exception exp)
            {
                exp.printStackTrace();
            }
        }
    }

    // ///////////////////////////////////////////
    private void parsePath(String path)
    {
        File tmp = new File(path);
        if (!tmp.isDirectory())
        {
            System.out.println("Should be directory");
            return;
        } else
        {
            File[] child = tmp.listFiles();
            for (int i = 0; i < child.length; i++)
            {
                if (child[i].isDirectory())
                {
                    parsePath(child[i].getAbsolutePath());
                } else
                    if (child[i].getName().endsWith(".java"))
                    {
                        parseFile(child[i].getAbsolutePath());
                    }
            }
        }
    }

    public static void main(String[] args)
    {
        try
        {
            JavaNet javaNet = new JavaNet();
            switch (args.length)
            {
                case 1:
                    if (args[0].equals("-h"))
                    {
                        System.out.println("should be as the following form:");
                        System.out
                                .println("\"-f {file's name} [-o {output's path}] [-x|-t]\"");
                        System.out
                                .println("\"-d {path's name} [-o {output's path}] [-x|-t]\"");
                        System.out
                                .println("Here, if output path is not specified, then the \"./result.txt\" path");
                        System.out
                                .println("will be used. And if the argument \"-x|-t\" is not used, then \"-t\" will");
                        System.out.println("used.");
                        System.out
                                .println("NODE: \"-x\" means the output form is xml form, and \"-t\" means text form");
                        System.out.println("\"-h\" will should this file");
                    } else
                    {
                        System.out.println("Argument Invalid");
                    }
                    System.exit(0);
                    break;
                case 2:
                    // set the input source's path
                    javaNet.setInputPath(args[1]);

                    // parse the source according to the specified.
                    if (args[0].equals("-f"))
                    {
                        javaNet.setParseForm(JavaNet.FILE);
                    } else
                        if (args[0].equals("-d"))
                        {
                            javaNet.setParseForm(JavaNet.DIRECTORY);
                        } else
                        {
                            System.out.println("Argument Invalid");
                        }
                    break;

                case 3:
                    // set the input source's path
                    javaNet.setInputPath(args[1]);

                    // set the output form
                    if (args[2].equals("-x"))
                    {
                        javaNet.setOutputForm(JavaNet.XML);
                    } else
                        if (args[2].equals("-t"))
                        {
                            javaNet.setOutputForm(JavaNet.TEXT);
                        } else
                        {
                            System.out.println("Argument Invalid");
                        }

                    // set the parse form of the parser
                    if (args[0].equals("-f"))
                    {
                        javaNet.setParseForm(JavaNet.FILE);
                    } else
                        if (args[0].equals("-d"))
                        {
                            javaNet.setParseForm(JavaNet.DIRECTORY);
                        } else
                        {
                            System.out.println("Argument Invalid");
                        }
                    break;

                case 4:
                    // set the input source's path
                    javaNet.setInputPath(args[1]);

                    // set the output source's path
                    javaNet.setOutputPath(args[3]);

                    // set the parse form of the parser
                    if (args[0].equals("-f"))
                    {
                        javaNet.setParseForm(JavaNet.FILE);
                    } else
                        if (args[0].equals("-d"))
                        {
                            javaNet.setParseForm(JavaNet.DIRECTORY);
                        } else
                        {
                            System.out.println("Argument Invalid");
                        }
                    break;

                case 5:
                    // set the input source's path
                    javaNet.setInputPath(args[1]);

                    // set the output source's path
                    javaNet.setOutputPath(args[3]);

                    // set the output form
                    if (args[4].equals("-x"))
                    {
                        javaNet.setOutputForm(JavaNet.XML);
                    } else
                        if (args[4].equals("-t"))
                        {
                            javaNet.setOutputForm(JavaNet.TEXT);
                        } else
                        {
                            System.out.println("Argument Invalid");
                        }

                    // set the parse form of the parser
                    if (args[0].equals("-f"))
                    {
                        javaNet.setParseForm(JavaNet.FILE);
                    } else
                        if (args[0].equals("-d"))
                        {
                            javaNet.setParseForm(JavaNet.DIRECTORY);
                        } else
                        {
                            System.out.println("Argument Invalid");
                        }
                    break;

                default:
                    System.out.println("Input Error");
                    System.exit(0);
                    break;
            }
            ;
            // begin to parse
            javaNet.parse();
        } catch (Exception e)
        {
            e.printStackTrace();
        }
    }
}